菜单组件需求分析
Element Plus 的 el-menu 提供了菜单的基础骨架,但在实际业务中,还需要大量定制:激活项的背景颜色、文字颜色、折叠状态的图标切换、嵌套子菜单的递归渲染等。本节分析 Element Plus Menu 的现状,明确需要封装的功能边界。
Element Plus Menu 的能力与不足
内置能力
| 能力 | 说明 |
|---|---|
| 水平/垂直模式 | mode="horizontal" / mode="vertical" |
| 折叠 | collapse 属性控制折叠/展开 |
| 子菜单 | el-sub-menu 嵌套实现多级菜单 |
| 激活项 | default-active 设置当前激活菜单项 |
| 主题 | background-color、text-color、active-text-color |
已废弃的属性
Element Plus 官方已将以下属性标记为废弃(deprecated):
| 废弃属性 | 替代方案 |
|---|---|
background-color | 使用 CSS 变量 --el-menu-bg-color |
text-color | 使用 CSS 变量 --el-menu-text-color |
active-text-color | 使用 CSS 变量 --el-menu-active-color |
这意味着我们需要通过 CSS 变量来设置菜单颜色,而非依赖 props。为了兼容未来版本,组件内部应该同时设置 props 和 CSS 变量。
封装目标
基于 Element Plus Menu,封装一个增强版的 Menu 组件,需要实现以下功能:
必需功能
- 数据驱动:通过
dataprop 传入菜单数据数组,自动渲染菜单结构。 - 递归渲染:支持任意层级的嵌套菜单,通过递归组件实现。
- 图标支持:每个菜单项可以配置 Iconify 图标。
- 折叠支持:
collapse属性控制菜单折叠/展开。 - 激活项管理:支持外部控制当前激活的菜单项。
增强功能
- 隐藏菜单项:通过
meta.hideMenu控制某些路由不在菜单中显示。 - 排序:通过
meta.order控制菜单项的显示顺序。 - Slot 自定义:提供插槽让用户自定义 Logo 区域和菜单项渲染。
组件结构设计
Menu(顶层容器)
├── Props: data, collapse, iconProps, ...
├── Slot: icon(Logo 区域)
├── Composable: useMenu(工具方法)
│ ├── generateMenuKeys(生成唯一 index)
│ ├── getIndex(获取菜单项 index)
│ └── menuHasChildren(判断是否有子菜单)
│
├── SubMenu(递归渲染引擎)
│ ├── 判断 children → MenuItem 或 SubMenu
│ └── Props: data, collapse, ...
│
└── MenuItem(单级菜单项)
├── 三种场景:无图标 / 侧栏 / 折叠
└── Props: data, collapse, disabled
text
菜单数据的类型定义
interface AppRouteMenuItem {
path: string
name?: string
meta?: RootMeta
redirect?: string
children?: AppRouteMenuItem[]
}
interface RootMeta {
title?: string
icon?: string
hideMenu?: boolean
order?: number
disabled?: boolean
key?: string // 运行时生成
[key: string]: unknown
}
typescript
为什么不使用 vxe-table 的菜单
vxe-table 等第三方组件库提供了更丰富的菜单功能,但引入额外依赖会增加包体积。Element Plus Menu 的基础功能已经能满足大多数后台需求,通过封装增强即可,无需更换底层组件。
本节小结
- 废弃属性:Element Plus Menu 的
background-color等属性已废弃,需使用 CSS 变量替代。 - 封装目标:数据驱动 + 递归渲染 + 图标支持 + 折叠 + 激活管理。
- 组件结构:Menu > SubMenu > MenuItem 三层结构,配合 useMenu composable。
- 类型定义:
AppRouteMenuItem和RootMeta定义菜单数据结构。
↑